package org.example.innocationHandler;

import com.typesafe.config.ConfigFactory;
import org.apache.pekko.actor.*;
import org.example.ContantVariable;
import org.example.Message;
import org.example.MessageType;
import org.example.inter.Productable;
import org.example.inter.RpcEndpoint;
import org.example.rpcendpoint.PekkoRpcEndpoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashSet;
import java.util.Set;

/**
 * @className: PekkoInvocationHandler
 * @Description: 返回一个 Productable 接口的动态代理，动态代理的 invoke 方法中通过 pekko 发送 method 名称，参数。
 * @Author: wangyifei
 * @Date: 2025/3/13 11:01
 */
public class PekkoInvocationHandler implements InvocationHandler , RpcEndpoint {
    private static Logger logger = LoggerFactory.getLogger(PekkoInvocationHandler.class);

    private ActorRef actorRef ;
    public PekkoInvocationHandler(){
        ActorSystem actorSystem = ActorSystem.create(ContantVariable.PEKKO_SYSTEM_NAME, ConfigFactory.load());
        actorRef = actorSystem.actorOf(Props.create(PekkoRpcEndpoint.class), ContantVariable.AGENT_URL);
    }
    public <T extends Productable> Productable builderProxy(Class<T> target){

        Class<?>[] interfaces1 = target.getInterfaces();

        Set<Class<Productable>> interfaces = new HashSet(interfaces1.length);
        for (Class<?> interfaze : interfaces1) {
            if (Productable.class.isAssignableFrom(interfaze)) {
                interfaces.add((Class<Productable>) interfaze);
            }
        }
        interfaces.add(Productable.class);
        //2. 新建动态代理的代码
        Productable o = (Productable)Proxy.newProxyInstance(this.getClass().getClassLoader()
                , interfaces.toArray(new Class[interfaces.size()])
                , this);
        return o ;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Message message = new Message(method.getName(), MessageType.INVOCATION , args , new Class[]{});
        logger.info("send msg");
        tell(message);
        return null;
    }

    @Override
    public void tell(Message msg) {
        System.out.println("tell");
        actorRef.tell(msg , ActorRef.noSender());
    }

    @Override
    public void ask(Message msg) {

    }
}
